#include "libgo/coroutine.h"
#include "net/client_impl.h"
#include "net/server_impl.h"
#include "net/msgpack.h"
#include <boost/lexical_cast.hpp>
#include <boost/thread.hpp>
#include "service/protocol/jrpc.h"
#include "service/register.h"
#include "libzqutil/log.h"
#include "curl/curl.h"
#include "libzqmysql/mysql_query.h"

using namespace libzq;
using namespace libzq::mysql;

void test_client()
{
	try
	{
		tcp::endpoint addr(address::from_string("127.0.0.1"), 43332);

		std::shared_ptr<tcp::socket> sock = std::shared_ptr<tcp::socket>(new tcp::socket(ioservice));
		sock->connect(addr);

		std::string data = "1234";
		MsgPacker msg(data);
		ClientImpl c = ClientImpl(sock);
		c.write(msg);

	}
	catch (std::exception& e)
	{
		LOGE(e.what());
	}
}

void test_client2(int idx)
{
	try
	{
		std::shared_ptr<ClientImpl> c = make_shared<ClientImpl>();
		if (c->connect("127.0.0.1", 43332))
		{
			c->start_serve();

			std::string data1 = boost::lexical_cast<std::string>(idx);
			MsgPacker msg1(data1);
			LOGT("msg total len %d, header len %d", msg1._total_len, msg1._header_len);
			c->write(msg1);
		}


		//c->stop();
	}
	catch (std::exception& e)
	{
		std::cout << "test_client2 ==> " << e.what() << std::endl;
	}
}

struct TableImpl
{
	TableImpl(const char* table) :_table(table) {}
	string _table;
};

struct USER : public TableImpl
{
	USER() :TableImpl("user") {}

	Field _uid{ "uid" };
	Field _phone{ "phone" };
};
int main(int argc, char** argv)
{
	if (argc < 3) {
		printf("Usage %s url concurrency\n", argv[0]);
		exit(1);
	}

	USER user;
	auto query_select = Query("user").select(user._uid, user._phone, SUM("uid"), COUNT("uid"))\
		.left_join(Query("user_info").select("nickname").on(Table("user").field("uid") = Table("user_info").field("uid")))\
		.filter(OR(AND(Field("uid") > 1000, Field("uid") < 10005), Field("phone") != nullptr)).orderby("-uid").limit(1);
	LOGI(query_select.to_string());

	auto query_insert = Insert("user").values(Field("uid") = "10001");
	LOGI(query_insert.to_string());

	auto quest_update = Update("user").set(Field("phone") = "123456789", Field("nickname") = "libzq-test").filter(Field("uid") = "10001");
	LOGI(quest_update.to_string());

	json11::Json o = json11::Json::object{ { "test", "1231" } };
	auto query_delete = Delete("user").filter(Field("uid") = "123");
	LOGI(query_delete.to_string());

	auto query_exist = Exist("user").filter(Field("uid") = "10001");
	LOGI(query_exist.to_string());

	auto r = join({ "1123", "1234" }, ",");
	LOGT(r);
	curl_global_init(CURL_GLOBAL_ALL);

	uint16_t port = atoi(argv[1]);
	int client_num = atoi(argv[2]);

	jrpc::HttpFinder::instance().init("http://127.0.0.1:43330/server-finder/");
	go[port]()
	{
		auto server = new jrpc::JsonServer();
		server->install_module("user", "./libuser.so.1.0");
		server->install_module("version", "./libversion.so.1.0");
		go std::bind(&ServerImpl::start_serve, server, "0.0.0.0", port);
		server->register_to(format("user@127.0.0.1:%d", port));
		server->register_to(format("version@127.0.0.1:%d", port));
	};

	for (int i = 0; i < client_num; i++)
	{
		go[]()
		{
			co_yield;
			while (1)
			{
				auto req = jrpc::JsonRequest::create("user", "login");
				auto o = json11::Json::object{ { "__method", "login" },{ "__args", json11::Json::object{ { "phone", "17600103921" },{ "password", "123456" } } } };
				auto resp = req->retry(3)->expire(3)->exec(o)->await();
				if (resp.is_error())
				{
					int32_t errnono;
					string errmsg;
					std::tie(errnono, errmsg) = resp.error();
					LOGE("Call method %s error %s(%d)", "login", errmsg, errnono);
				}
				else
				{
					LOGT("Get method %s resp %s", "login", resp.dumps());
				}
				co_sleep(1500);
			}
		};

	}

	boost::thread_group tg;
	for (int i = 0; i < 8; ++i)
		tg.create_thread([] {
		co_sched.RunUntilNoTask();
	});
	tg.join_all();
	return 0;
}